'''

    Doodling with the PyUSB package...


'''


import usb.core
import usb.util
import sys, os


os.environ['PYUSB_DEBUG_LEVEL'] = 'debug'

KP_VENDOR = 1493
KP_PRODUCT = 26498
CY_VENDOR = 1699
CY_PRODUCT = 32961

class find_class(object):
    def __init__(self, class_):
        self._class = class_

    def __call__(self, device):
        # first, let's check the device
        if device.bDeviceClass == self._class:
            return True
        # if not found, transverse all devices to find an
        # interface that matches our class
        for cfg in device:
            # find_descriptor: what's it?
            intf = usb.util.find_descriptor(
                                        cfg,
                                        bInterfaceClass=self._class
                                )
            if intf is not None:
                return True
        
        return False

def scan_hid():
    print 'Scanning for HID devices'
    devs = usb.core.find(find_all=1, custom_match=find_class(usb.CLASS_HID))
    return devs

def detail_scan(idProduct=None):
    import usb
     
    busses = usb.busses()
     
    for bus in busses:
      devices = bus.devices
      for dev in devices:
        if idProduct and dev.idProduct != idProduct:
            continue
        print "Device:", dev.filename
        print "  Device class:",dev.deviceClass
        print "  Device sub class:",dev.deviceSubClass
        print "  Device protocol:",dev.deviceProtocol
        print "  Max packet size:",dev.maxPacketSize
        print "  idVendor:",dev.idVendor
        print "  idProduct:",dev.idProduct
        print "  Device Version:",dev.deviceVersion
        for config in dev.configurations:
          print "  Configuration:", config.value
          print "    Total length:", config.totalLength 
          print "    selfPowered:", config.selfPowered
          print "    remoteWakeup:", config.remoteWakeup
          print "    maxPower:", config.maxPower
          for intf in config.interfaces:
            print "    Interface:",intf[0].interfaceNumber
            for alt in intf:
              print "    Alternate Setting:",alt.alternateSetting
              print "      Interface class:",alt.interfaceClass
              print "      Interface sub class:",alt.interfaceSubClass
              print "      Interface protocol:",alt.interfaceProtocol
              for ep in alt.endpoints:
                print "      Endpoint:",hex(ep.address)
                print "        Type:",ep.type
                print "        Max packet size:",ep.maxPacketSize
                print "        Interval:",ep.interval

def print_device(dev):
    #print '\n'.join(dir(dev))
    print "Device Class:", dev, dev.bDeviceClass
    print "    subclass:", dev.bDeviceSubClass
    print "    protocol:", dev.bDeviceProtocol
    print "   dsec type:", dev.bDescriptorType
    print "    idVendor:",dev.idVendor
    print "   idProduct:",dev.idProduct
    for cfg in dev:
        print '\tConfig value:', cfg.bConfigurationValue

def getStringDescriptor(device, index): 
    """ 
    """ 
    response = device.ctrl_transfer(usb.util.ENDPOINT_IN, 
                                    usb.legacy.REQ_GET_DESCRIPTOR, 
                                    (usb.util.DESC_TYPE_STRING << 8) | index, 
                                    0, # language id 
                                    255) # length 

    # TODO: Refer to 'libusb_get_string_descriptor_ascii' for error handling 
    
    return response[2:].tostring().decode('utf-16') 

def KP():
    if 1:
        detail_scan(KP_PRODUCT)                
    if 0:
        for dev in scan_hid():
            print_device(dev)

    kp_dev = usb.core.find(idVendor=KP_VENDOR, idProduct=KP_PRODUCT)
    if kp_dev is None:
        raise Exception("Numeric KeyPad not connected")

    print_device(kp_dev)
    
    print " ACTIVE CFG:"
    print "    ", kp_dev.get_active_configuration()
    kp_dev.set_configuration() # use first config
    kp_dev.set_interface_altsetting(interface = 1, alternate_setting = 1)

    print 20*'#'
    # get an endpoint instance
    ep = usb.util.find_descriptor(
            dev.get_interface_altsetting(),   # first interface
            # match the first OUT endpoint
            custom_match = \
                lambda e: \
                    usb.util.endpoint_direction(e.bEndpointAddress) == \
                    usb.util.ENDPOINT_IN
        )
    
    assert ep is not None
    
    # write the data
    ep.write('test')



def CY():
    if 0:
        for dev in scan_hid():
            print_device(dev)
    if 1:
        detail_scan(CY_PRODUCT)                

    cy_dev = usb.core.find(idVendor=CY_VENDOR, idProduct=CY_PRODUCT)
    if cy_dev is None:
        raise Exception("Saitek Cyborg not connected")

    print_device(cy_dev)
    #print '\n'.join(dir(cy_dev))
    
    print " DESC:"
    print "    ", getStringDescriptor(cy_dev,0)
    
    print " ACTIVE CFG:"
    print "     ", cy_dev.get_active_configuration()
    
    #cy_dev.set_configuration() # use first config

    #ret = cy_dev.read(0x81, , 0, 100)


if __name__ == '__main__':
    #KP()
    CY()
